﻿using System;
using System.IO;
using System.Text;
using System.Runtime.CompilerServices;
using BanZuiCloudControlAgent.Utils.Common;
using NLog;
using NLog.Config;
using NLog.Targets;

namespace BanZuiCloudControlAgent.Utils.Logging
{
    /// <summary>
    /// 日志记录器，封装NLog功能
    /// </summary>
    public class Logger
    {
        private readonly NLog.Logger _logger;

        /// <summary>
        /// 日志事件参数
        /// </summary>
        public class LogEventArgs : EventArgs
        {
            /// <summary>
            /// 时间戳
            /// </summary>
            public DateTime Timestamp { get; }

            /// <summary>
            /// 日志级别
            /// </summary>
            public string Level { get; }

            /// <summary>
            /// 日志记录器名称
            /// </summary>
            public string LoggerName { get; }

            /// <summary>
            /// 日志消息
            /// </summary>
            public string Message { get; }

            /// <summary>
            /// 异常信息
            /// </summary>
            public Exception Exception { get; }

            /// <summary>
            /// 构造函数
            /// </summary>
            public LogEventArgs(
                DateTime timestamp,
                string level,
                string loggerName,
                string message,
                Exception exception = null
            )
            {
                Timestamp = timestamp;
                Level = level;
                LoggerName = loggerName;
                Message = message;
                Exception = exception;
            }
        }

        /// <summary>
        /// 日志事件，由静态类管理
        /// </summary>
        public static event EventHandler<LogEventArgs> LogWritten;

        /// <summary>
        /// 触发日志事件
        /// </summary>
        private static void OnLogWritten(
            DateTime timestamp,
            string level,
            string loggerName,
            string message,
            Exception exception = null
        )
        {
            LogWritten?.Invoke(
                null,
                new LogEventArgs(timestamp, level, loggerName, message, exception)
            );
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="name">日志记录器名称</param>
        public Logger(string name)
        {
            _logger = NLog.LogManager.GetLogger(name);
        }

        /// <summary>
        /// 记录调试级别日志
        /// </summary>
        public void Debug(string message)
        {
            var logEvent = new LogEventInfo(LogLevel.Debug, _logger.Name, message);
            
            // 获取调用者信息
            var frame = new System.Diagnostics.StackFrame(1, true);
            var fileName = frame.GetFileName();
            var lineNumber = frame.GetFileLineNumber();
            var method = frame.GetMethod();
            
            if (method != null)
            {
                // 只使用文件名，不使用完整路径
                string shortFileName = fileName != null ? Path.GetFileName(fileName) : null;
                logEvent.SetCallerInfo(method.DeclaringType?.FullName, shortFileName, method.Name, lineNumber);
            }
            
            _logger.Log(logEvent);
            OnLogWritten(DateTime.Now, "DEBUG", _logger.Name, message);
        }

        /// <summary>
        /// 记录调试级别日志（带异常信息）
        /// </summary>
        public void Debug(string message, Exception ex)
        {
            var logEvent = new LogEventInfo(LogLevel.Debug, _logger.Name, message);
            logEvent.Exception = ex;
            
            // 获取调用者信息
            var frame = new System.Diagnostics.StackFrame(1, true);
            var fileName = frame.GetFileName();
            var lineNumber = frame.GetFileLineNumber();
            var method = frame.GetMethod();
            
            if (method != null)
            {
                // 只使用文件名，不使用完整路径
                string shortFileName = fileName != null ? Path.GetFileName(fileName) : null;
                logEvent.SetCallerInfo(method.DeclaringType?.FullName, shortFileName, method.Name, lineNumber);
            }
            
            _logger.Log(logEvent);
            OnLogWritten(DateTime.Now, "DEBUG", _logger.Name, message, ex);
        }

        /// <summary>
        /// 记录调试级别日志（格式化）
        /// </summary>
        public void Debug(string format, params object[] args)
        {
            string message = string.Format(format, args);
            var logEvent = new LogEventInfo(LogLevel.Debug, _logger.Name, message);
            
            // 获取调用者信息
            var frame = new System.Diagnostics.StackFrame(1, true);
            var fileName = frame.GetFileName();
            var lineNumber = frame.GetFileLineNumber();
            var method = frame.GetMethod();
            
            if (method != null)
            {
                // 只使用文件名，不使用完整路径
                string shortFileName = fileName != null ? Path.GetFileName(fileName) : null;
                logEvent.SetCallerInfo(method.DeclaringType?.FullName, shortFileName, method.Name, lineNumber);
            }
            
            _logger.Log(logEvent);
            OnLogWritten(DateTime.Now, "DEBUG", _logger.Name, message);
        }

        /// <summary>
        /// 记录信息级别日志
        /// </summary>
        public void Info(string message)
        {
            var logEvent = new LogEventInfo(LogLevel.Info, _logger.Name, message);
            
            // 获取调用者信息
            var frame = new System.Diagnostics.StackFrame(1, true);
            var fileName = frame.GetFileName();
            var lineNumber = frame.GetFileLineNumber();
            var method = frame.GetMethod();
            
            if (method != null)
            {
                // 只使用文件名，不使用完整路径
                string shortFileName = fileName != null ? Path.GetFileName(fileName) : null;
                logEvent.SetCallerInfo(method.DeclaringType?.FullName, shortFileName, method.Name, lineNumber);
            }
            
            _logger.Log(logEvent);
            OnLogWritten(DateTime.Now, "INFO", _logger.Name, message);
        }

        /// <summary>
        /// 记录信息级别日志（带异常信息）
        /// </summary>
        public void Info(string message, Exception ex)
        {
            var logEvent = new LogEventInfo(LogLevel.Info, _logger.Name, message);
            logEvent.Exception = ex;
            
            // 获取调用者信息
            var frame = new System.Diagnostics.StackFrame(1, true);
            var fileName = frame.GetFileName();
            var lineNumber = frame.GetFileLineNumber();
            var method = frame.GetMethod();
            
            if (method != null)
            {
                // 只使用文件名，不使用完整路径
                string shortFileName = fileName != null ? Path.GetFileName(fileName) : null;
                logEvent.SetCallerInfo(method.DeclaringType?.FullName, shortFileName, method.Name, lineNumber);
            }
            
            _logger.Log(logEvent);
            OnLogWritten(DateTime.Now, "INFO", _logger.Name, message, ex);
        }

        /// <summary>
        /// 记录信息级别日志（格式化）
        /// </summary>
        public void Info(string format, params object[] args)
        {
            string message = string.Format(format, args);
            var logEvent = new LogEventInfo(LogLevel.Info, _logger.Name, message);
            
            // 获取调用者信息
            var frame = new System.Diagnostics.StackFrame(1, true);
            var fileName = frame.GetFileName();
            var lineNumber = frame.GetFileLineNumber();
            var method = frame.GetMethod();
            
            if (method != null)
            {
                // 只使用文件名，不使用完整路径
                string shortFileName = fileName != null ? Path.GetFileName(fileName) : null;
                logEvent.SetCallerInfo(method.DeclaringType?.FullName, shortFileName, method.Name, lineNumber);
            }
            
            _logger.Log(logEvent);
            OnLogWritten(DateTime.Now, "INFO", _logger.Name, message);
        }

        /// <summary>
        /// 记录警告级别日志
        /// </summary>
        public void Warn(string message)
        {
            var logEvent = new LogEventInfo(LogLevel.Warn, _logger.Name, message);
            
            // 获取调用者信息
            var frame = new System.Diagnostics.StackFrame(1, true);
            var fileName = frame.GetFileName();
            var lineNumber = frame.GetFileLineNumber();
            var method = frame.GetMethod();
            
            if (method != null)
            {
                // 只使用文件名，不使用完整路径
                string shortFileName = fileName != null ? Path.GetFileName(fileName) : null;
                logEvent.SetCallerInfo(method.DeclaringType?.FullName, shortFileName, method.Name, lineNumber);
            }
            
            _logger.Log(logEvent);
            OnLogWritten(DateTime.Now, "WARN", _logger.Name, message);
        }

        /// <summary>
        /// 记录警告级别日志（带异常信息）
        /// </summary>
        public void Warn(string message, Exception ex)
        {
            var logEvent = new LogEventInfo(LogLevel.Warn, _logger.Name, message);
            logEvent.Exception = ex;
            
            // 获取调用者信息
            var frame = new System.Diagnostics.StackFrame(1, true);
            var fileName = frame.GetFileName();
            var lineNumber = frame.GetFileLineNumber();
            var method = frame.GetMethod();
            
            if (method != null)
            {
                // 只使用文件名，不使用完整路径
                string shortFileName = fileName != null ? Path.GetFileName(fileName) : null;
                logEvent.SetCallerInfo(method.DeclaringType?.FullName, shortFileName, method.Name, lineNumber);
            }
            
            _logger.Log(logEvent);
            OnLogWritten(DateTime.Now, "WARN", _logger.Name, message, ex);
        }

        /// <summary>
        /// 记录警告级别日志（格式化）
        /// </summary>
        public void Warn(string format, params object[] args)
        {
            string message = string.Format(format, args);
            var logEvent = new LogEventInfo(LogLevel.Warn, _logger.Name, message);
            
            // 获取调用者信息
            var frame = new System.Diagnostics.StackFrame(1, true);
            var fileName = frame.GetFileName();
            var lineNumber = frame.GetFileLineNumber();
            var method = frame.GetMethod();
            
            if (method != null)
            {
                // 只使用文件名，不使用完整路径
                string shortFileName = fileName != null ? Path.GetFileName(fileName) : null;
                logEvent.SetCallerInfo(method.DeclaringType?.FullName, shortFileName, method.Name, lineNumber);
            }
            
            _logger.Log(logEvent);
            OnLogWritten(DateTime.Now, "WARN", _logger.Name, message);
        }

        /// <summary>
        /// 记录错误级别日志
        /// </summary>
        public void Error(string message)
        {
            var logEvent = new LogEventInfo(LogLevel.Error, _logger.Name, message);
            
            // 获取调用者信息
            var frame = new System.Diagnostics.StackFrame(1, true);
            var fileName = frame.GetFileName();
            var lineNumber = frame.GetFileLineNumber();
            var method = frame.GetMethod();
            
            if (method != null)
            {
                // 只使用文件名，不使用完整路径
                string shortFileName = fileName != null ? Path.GetFileName(fileName) : null;
                logEvent.SetCallerInfo(method.DeclaringType?.FullName, shortFileName, method.Name, lineNumber);
            }
            
            _logger.Log(logEvent);
            OnLogWritten(DateTime.Now, "ERROR", _logger.Name, message);
        }

        /// <summary>
        /// 记录错误级别日志（带异常信息）
        /// </summary>
        public void Error(string message, Exception ex)
        {
            var logEvent = new LogEventInfo(LogLevel.Error, _logger.Name, message);
            logEvent.Exception = ex;
            
            // 获取调用者信息
            var frame = new System.Diagnostics.StackFrame(1, true);
            var fileName = frame.GetFileName();
            var lineNumber = frame.GetFileLineNumber();
            var method = frame.GetMethod();
            
            if (method != null)
            {
                // 只使用文件名，不使用完整路径
                string shortFileName = fileName != null ? Path.GetFileName(fileName) : null;
                logEvent.SetCallerInfo(method.DeclaringType?.FullName, shortFileName, method.Name, lineNumber);
            }
            
            _logger.Log(logEvent);
            OnLogWritten(DateTime.Now, "ERROR", _logger.Name, message, ex);
        }

        /// <summary>
        /// 记录错误级别日志（格式化）
        /// </summary>
        public void Error(string format, params object[] args)
        {
            string message = string.Format(format, args);
            var logEvent = new LogEventInfo(LogLevel.Error, _logger.Name, message);
            
            // 获取调用者信息
            var frame = new System.Diagnostics.StackFrame(1, true);
            var fileName = frame.GetFileName();
            var lineNumber = frame.GetFileLineNumber();
            var method = frame.GetMethod();
            
            if (method != null)
            {
                // 只使用文件名，不使用完整路径
                string shortFileName = fileName != null ? Path.GetFileName(fileName) : null;
                logEvent.SetCallerInfo(method.DeclaringType?.FullName, shortFileName, method.Name, lineNumber);
            }
            
            _logger.Log(logEvent);
            OnLogWritten(DateTime.Now, "ERROR", _logger.Name, message);
        }

        /// <summary>
        /// 记录致命级别日志
        /// </summary>
        public void Fatal(string message)
        {
            var logEvent = new LogEventInfo(LogLevel.Fatal, _logger.Name, message);
            
            // 获取调用者信息
            var frame = new System.Diagnostics.StackFrame(1, true);
            var fileName = frame.GetFileName();
            var lineNumber = frame.GetFileLineNumber();
            var method = frame.GetMethod();
            
            if (method != null)
            {
                // 只使用文件名，不使用完整路径
                string shortFileName = fileName != null ? Path.GetFileName(fileName) : null;
                logEvent.SetCallerInfo(method.DeclaringType?.FullName, shortFileName, method.Name, lineNumber);
            }
            
            _logger.Log(logEvent);
            OnLogWritten(DateTime.Now, "FATAL", _logger.Name, message);
        }

        /// <summary>
        /// 记录致命级别日志（带异常信息）
        /// </summary>
        public void Fatal(string message, Exception ex)
        {
            var logEvent = new LogEventInfo(LogLevel.Fatal, _logger.Name, message);
            logEvent.Exception = ex;
            
            // 获取调用者信息
            var frame = new System.Diagnostics.StackFrame(1, true);
            var fileName = frame.GetFileName();
            var lineNumber = frame.GetFileLineNumber();
            var method = frame.GetMethod();
            
            if (method != null)
            {
                // 只使用文件名，不使用完整路径
                string shortFileName = fileName != null ? Path.GetFileName(fileName) : null;
                logEvent.SetCallerInfo(method.DeclaringType?.FullName, shortFileName, method.Name, lineNumber);
            }
            
            _logger.Log(logEvent);
            OnLogWritten(DateTime.Now, "FATAL", _logger.Name, message, ex);
        }

        /// <summary>
        /// 记录致命级别日志（格式化）
        /// </summary>
        public void Fatal(string format, params object[] args)
        {
            string message = string.Format(format, args);
            var logEvent = new LogEventInfo(LogLevel.Fatal, _logger.Name, message);
            
            // 获取调用者信息
            var frame = new System.Diagnostics.StackFrame(1, true);
            var fileName = frame.GetFileName();
            var lineNumber = frame.GetFileLineNumber();
            var method = frame.GetMethod();
            
            if (method != null)
            {
                // 只使用文件名，不使用完整路径
                string shortFileName = fileName != null ? Path.GetFileName(fileName) : null;
                logEvent.SetCallerInfo(method.DeclaringType?.FullName, shortFileName, method.Name, lineNumber);
            }
            
            _logger.Log(logEvent);
            OnLogWritten(DateTime.Now, "FATAL", _logger.Name, message);
        }

        /// <summary>
        /// 初始化NLog配置
        /// </summary>
        public static void InitializeNLog()
        {
            try
            {
                // 不创建配置，使用外部nlog.config文件
                // NLog会自动加载配置文件，无需手动配置
                Console.WriteLine("使用外部nlog.config配置文件");
                
                // 确保日志目录存在
                var logFilePath = Utils.Common.ConfigurationManager.GetLogFilePath("app.log");
                string logDirectory = Path.GetDirectoryName(logFilePath);
                if (!Directory.Exists(logDirectory))
                {
                    Directory.CreateDirectory(logDirectory);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"初始化NLog配置失败: {ex.Message}");
                throw;
            }
        }
    }
}
